package com.hourse.app.controller.web;

import com.hourse.app.service.impl.OkxWebSocketClient;
import com.hourse.app.config.OkxWebSocketConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint(value = "/marketPublicSocket")
@Component
@Slf4j
public class MarketPublicSocket {

  private static final OkxWebSocketClient webSocketClient = new OkxWebSocketClient();

  //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
  private static int onlineCount = 0;

  //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
  private static CopyOnWriteArraySet<MarketPublicSocket> webSocketSet = new CopyOnWriteArraySet<MarketPublicSocket>();

  //与某个客户端的连接会话，需要通过它来给客户端发送数据
  private Session session;

  /**
   * 连接建立成功调用的方法
   */
  @OnOpen
  public void onOpen(Session session) {
    this.session = session;
    //加入set中
    webSocketSet.add(this);
    if (onlineCount == 0) {
      getOkxInfo();
    }
    //在线数加1
    addOnlineCount();
    System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
    try {
      sendMessage("总连接数" + onlineCount + "");
    } catch (IOException e) {
      System.out.println("IO异常");
    }
  }

  /**
   * @描述 ：【获取欧易公共行情数据】
   * @作者 ：lichenguang
   * @时间 ：2022/3/23 13:51
   */
  private void getOkxInfo() {
    //与服务器建立连接
    OkxWebSocketConfig.publicConnect(webSocketClient);
    // 新建第一个连接时，连接OKX的SOCKET,不为0，则说明建立有连接
    this.booksChannelBTCUSDT();
  }

  /**
   * 连接关闭调用的方法
   */
  @OnClose
  public void onClose() {
    //从set中删除
    webSocketSet.remove(this);
    //在线数减1
    subOnlineCount();

    if (onlineCount == 0) {
      OkxWebSocketClient.closeConnection();
    }

    System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
  }

  /**
   * 收到客户端消息后调用的方法
   *
   * @param message 客户端发送过来的消息
   */
  @OnMessage
  public void onMessage(String message, Session session) {
    System.out.println("来自客户端的消息:" + message);

    //群发消息
    for (MarketPublicSocket item : webSocketSet) {
      try {
        item.sendMessage(message);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 发生错误时调用
   */
  public void onError(Session session, Throwable error) {
    System.out.println("发生错误");
    error.printStackTrace();
  }

  public void sendMessage(String message) throws IOException {
    this.session.getBasicRemote().sendText(message);
    this.session.getAsyncRemote().sendText(message);
  }


  /**
   * 群发自定义消息
   */
  public static void sendInfo(String message) throws IOException {
    for (MarketPublicSocket item : webSocketSet) {
      try {
        item.sendMessage(message);
      } catch (IOException e) {
        continue;
      }
    }
  }

  public static synchronized int getOnlineCount() {
    return onlineCount;
  }

  public static synchronized void addOnlineCount() {
    MarketPublicSocket.onlineCount++;
  }

  public static synchronized void subOnlineCount() {
    MarketPublicSocket.onlineCount--;
  }

  /**
   * @描述 ：【欧易行情频道】
   * @作者 ：lichenguang
   * @时间 ：2022/3/23 13:52
   */
  public void tickersChannel() {
    //添加订阅频道
    ArrayList<Map> channelList = new ArrayList<>();
    Map spotTickerMap = new HashMap();
    spotTickerMap.put("channel", "tickers");
    spotTickerMap.put("instId", "BTC-USDT");
    channelList.add(spotTickerMap);
    //调用订阅方法
    OkxWebSocketClient.subscribe(channelList);
  }

  public void booksChannelBTCUSDT() {
    //添加订阅频道
    ArrayList<Map> channelList = new ArrayList<>();

    Map map = new HashMap();
    map.put("channel", "books5");
    map.put("instId", "BTC-USDT");

    channelList.add(map);
    //调用订阅方法
    OkxWebSocketClient.subscribe(channelList);
  }
}
